/**
 * Dispatcher Definition
 *
 * @namespace ISS.Ajax
 * @module dispatcher
 * @requires ISS
 * @requires popup
 * @requires jquery
 * @requires event
 * @requires dom
 * @requires connection
 */

ISS.namespace("Ajax");
(function() {
	$L = ISS.lang;
		
	/**
	 * The ajax caller
	 * @class Caller
	 * @static
	 */
	ISS.Ajax.Caller = function() {
	  	var obj = {};
        obj.submit = function (uri, form) {

            ISS.Popup.Windows.Show_Loading();
            // AJAX url don't work with &amp;
            while (uri.indexOf ( '&amp;' ) > -1) {
                uri = uri.replace ( '&amp;', '&' );
            }

            // Ajax calling to remote server
            form.ajaxSubmit(
            {
	            url: uri, 
	            type:"POST",				//request is a POSt request
	            dataType: "json",           //expect json as return
	            success: function(result)   //trigger this on success
	            {
	            	ISS.Ajax.Dispatcher.dispatch(result);
	                ISS.Popup.Windows.Hide_Loading();
	            }
            });
        };

	  	/**
		 * @description Sending request to remote URL
		 * @method request
		 * @public
		 * @param {String} uri     	Remote URL
		 * @param {Object} param	Used to pass the user parameter
		 * @return void
		 */
		obj.request = function (uri, param) {

			ISS.Popup.Windows.Show_Loading();
			// AJAX url don't work with &amp;
			while (uri.indexOf ( '&amp;' ) > -1) {
			    uri = uri.replace ( '&amp;', '&' );
			}

			// Create remote uri with parameter in Kohana format.
			uri = ISS.Ajax.Dispatcher.augmentURI(uri, param);
			// Ajax calling to remote server
			$.ajax(
			{
				url: uri, 
				type:"POST",				//request is a POSt request
				dataType: "json",			//expect json as return
				success: function(result) 	//trigger this on success
				{
					ISS.Ajax.Dispatcher.dispatch(result);
					ISS.Popup.Windows.Hide_Loading();
				}
			});
		};
		
	  	/**
		* @description Returns a string representing the dispatcher ajax.
		* @method toString
		* @return {String}
		*/
		obj.toString = function() {
		    return ("Soft Square Caller Ajax");
		};

		return obj;
	}();
	
	/********************** End ISS.Ajax.Caller Class **********************/
	
	/**
	 * The ajax dispatcher
	 * @class Dispatcher
	 * @static
	 */
	ISS.Ajax.Dispatcher = function() {
	  	var obj = {},

		// Constants
		constants = {
			// Ajax Type
			UPDATE_VIEW: 'updateView',
			SCRIPT_BLOCK: 'scriptBlock',
			
			// Ajax content element
			AJAX_SIZE: 0,
			AJAX_TYPE: 1,
			AJAX_ID: 2,
			AJAX_CONTENT: 3,
			END_TOKEN: 4,	// Maximum element
			
			// Ajax content element separator
			TOKEN_SEPARATOR: '|'
				
		};
	  	
		_reURI = {
				key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
				q:   {
					name:   "queryKey",
					parser: /(?:^|&)([^&=]*)=?([^&]*)/g
				},
				parser: {
					strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
					loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
				}
		},
		_reTrim = /^\s+|\s+$/g;	  	
		
		/**
		 * @description Update view from a html content
		 * @method _update
		 * @private
		 * @param {string} selector Selector id for update
		 * @param {string} content	Content to update
		 */
		function _update(selector, content) {
			try {
				$("#" + selector).replaceWith(content);
			} catch (e) {
				throw new Error("Dispacher: Update View Error ("+e+")");
			}
		};
		
		/**
		 * @description Executing a javascript script segment
		 * @method _exec
		 * @private
		 * @param {string} script	Script to execite	Content to execute
		 * @param {Object} config    User configuration (useful for future implementations)
		 */
		function _exec(script) {
		  if (script && (script !== '')) {
			try{
				// Execute javascript script segment
				eval(script);
			} catch(e) {
				throw new Error("Dispacher: Script Execution Error ("+e+")");
			}
		  }
		};
	  	
		/**
		 * @description Dispatching the content from server response
		 * @method dispatch
		 * @public
		 * @param {string} content	Content string from server
		 * @return void
		 */
		obj.dispatch = function (content) {
			if (content.length>0) {
				
				var ajax_content = new Array();		// Command container
				var content_block = new Array();	// Content container
				var token_command = 0;				// Command counter
				var token_content = 0;				// Element counter
			
				var token_element = content.split(constants.TOKEN_SEPARATOR);		// Split each token 
				
				// Parser for each token
				for(i = 0; i < token_element.length; i++) {
					
					// Get next element
			    	content_block[token_content] = token_element[i];
			    	token_content++;
					// Process for a single command
			    	if (token_content >= constants.END_TOKEN) {
						token_command++;			// Increate command counter
						token_content = 0;			// Reset content element
//FIXME Encoding content size is difference between caller & callee						
//						if (content_block[constants.AJAX_SIZE] == content_block[constants.AJAX_CONTENT].length) {
							if (content_block[constants.AJAX_TYPE] === constants.UPDATE_VIEW) {
								// Process update view
								_update(content_block[constants.AJAX_ID], content_block[constants.AJAX_CONTENT]);
							}
							else if (content_block[constants.AJAX_TYPE] === constants.SCRIPT_BLOCK) {
								// Process execute javascript
								_exec(content_block[constants.AJAX_CONTENT]);
							}
//FIXME Encoding content size is difference between caller & callee
//						}
//						else {
//							// Dispatch error.
//							alert('Ajax dispatch error!');
//						}
						// Reinitialize content container
						content_block = new Array();
					}
			    }
			}
			return null;
		};
		
		/*
		 parseUri 1.2.1
		 (c) 2007 Steven Levithan <stevenlevithan.com>
		 MIT License
		*/
		function _parseUri (str, strictMode) {
			var	o   = _reURI,
				m   = o.parser[strictMode?"strict":"loose"].exec(str),
				uri = {},
				i   = 14;
		
			while (i--) uri[o.key[i]] = m[i] || "";
			uri[o.q.name] = {};
			uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
				if ($1) uri[o.q.name][$1] = $2;
			});
			return uri;
		}; 
		
		/**
	     * @description augment an url with more parameters, overriding...
	     * @method augmentURI
	     * @public
	     * @param {string} url			url that should be expanded with new arguments
	     * @param {array} m	MoreParams:	associative array {param1:value1, param2:value2}
	     * @return string
	    */
	    obj.augmentURI = function( url, m ) {
	    	m = m || {};
		    var o = _parseUri(url, this.strictMode),
		        u = '';
			o.queryKey = o.queryKey || {};
			$L.augmentObject(o.queryKey, m, true);
			if (o.protocol) u += o.protocol + ':';
			if (this.strictMode) {
				if (/^(?:[^:\/?#]+:)?\/\//.test(o.source)) u += '//';
			} else {
				if (/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?\/\//.test(o.source)) u += '//';
			}
			if (o.authority) {
				if (o.userInfo) {
					if (o.user) u += o.user;
					if (o.userInfo.indexOf(':') > -1) u += ':';
					if (o.password) u += o.password;
					u += '@';
				}
				if (o.host) u += o.host;
				if (o.port) u += ':' + o.port;
			}
			if (o.relative) {
				if (o.path) {
					if (o.directory) u += o.directory;
					if (o.file) u += o.file;
				}
				// Kohana don't use ? parameter format
				//u += '?';// + o.query
				for (sName in o.queryKey) {
					if (o.queryKey.hasOwnProperty(sName)) {
						// Kohana don't use & separate argument
						//u += sName+'='+o.queryKey[sName]+'&';
						//if (u[u.lenght-1]=='/')
						if (u.charAt(u.length-1) != '/') {
							u += '/';
						}
						u += o.queryKey[sName];	// Kohana segment separator
					}
				}
				if (o.anchor) u += '#' + o.anchor;
			}
			return u;
	    };
		
		/**
		* @description Returns a string representing the dispatcher ajax.
		* @method toString
		* @return {String}
		*/
		obj.toString = function() {
		    return ("Soft Square Dispatcher Ajax");
		};

		return obj;

	}();
	
	/********************** End ISS.Ajax.Dispatcher Class **********************/

})();